/*
一个既是static又是final的字段只会分配一块不能改变的存储空间。

当 final关键字 与 对象引用 而非 基本类型 一起使用时，其含义可能会令人困惑。
对于基本类型，final使其值恒定不变，但对于对象引用，final使引用恒定不变。
一旦引用被初始化为一个对象，它就永远不能被更改为指向另一个对象了。
但是，对象本身是 可以修改的。Java没有提供使对象恒定不变的方法。（但是，你可以编写类，使对象具有恒定不变的效果。）
这个限制同样适用于数组，它们也是对象。
 */

import java.util.Random;

class Value {
    int i;

    Value(int i) {
        this.i = i;
    }
}

public class FinalDemo {
    private static Random random = new Random(47);
    private String str;

    public FinalDemo(String str) {
        this.str = str;
    }

    // 可以是编译时常量
    private final int final_int_var = 1;
    private static final int static_final_int_var = 2;
    // 典型的公共常量
    public static final int pub_static_final_int_var = 3;
    // 不能作为编译时常量
    private final int final_rand_var = random.nextInt(100);
    static final int static_final_rand_var = random.nextInt(100);
    private Value value_obj = new Value(10);
    private final Value final_value_obj = new Value(20);
    private static final Value static_final_value_obj = new Value(30);
    // 数组
    private final int[] final_array = {1, 2, 3, 4, 5};

    @Override
    public String toString() {
        return "str: " + str + "\n" +
                "final_int_var: " + final_int_var + "\n" +
                "static_final_int_var: " + static_final_int_var + "\n" +
                "pub_static_final_int_var: " + pub_static_final_int_var + "\n" +
                "final_rand_var: " + final_rand_var + "\n" +
                "static_final_rand_var: " + static_final_rand_var + "\n";
    }

    public static void main(String[] args) {
        FinalDemo f1 = new FinalDemo("F1");
        System.out.println(f1);
//        f1.final_int_var++;  // 错误，值是不可改变的
        f1.final_value_obj.i++; // 对象非恒定不变
        f1.value_obj = new Value(100);  // 没问题，不是final
        for (int i = 0; i < f1.final_array.length; i++) {
            f1.final_array[i]++;  // 对象非恒定不变
        }
//        f1.final_value_obj = new Value(200); // 错误，final引用不能被改变
//        f1.static_final_value_obj = new Value(200); // 错误，final引用不能被改变
//        f1.final_array = new int[]{1, 2, 3}; // 错误，final引用不能被改变
        System.out.println(f1);
        System.out.println("-----------------");
        FinalDemo f2 = new FinalDemo("F2");
        System.out.println(f1);
        System.out.println(f2);
    }
}
